<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.2.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/murmur/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/murmur/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/murmur/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/murmur/images/logo.svg" color="#222">

<link rel="stylesheet" href="/murmur/css/main.css">



<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.1/css/all.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.css">
  <script src="//cdn.jsdelivr.net/npm/nprogress@0.2.0/nprogress.js"></script>

<script class="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"gitee.com","root":"/murmur/","scheme":"Gemini","version":"8.0.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":true,"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":"disqus","storage":true,"lazyload":false,"nav":null},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}};
  </script>

  <meta name="description" content="演示自定义指令案例，通读了解指令相关API，最后了解指令的解析运行原理">
<meta property="og:type" content="article">
<meta property="og:title" content="掌握与使用Vue指令">
<meta property="og:url" content="https://gitee.com/lianghuilin/murmur.git/crush_notes/%E6%8E%8C%E6%8F%A1%E4%B8%8E%E4%BD%BF%E7%94%A8Vue%E6%8C%87%E4%BB%A4/index.html">
<meta property="og:site_name" content="汇话板">
<meta property="og:description" content="演示自定义指令案例，通读了解指令相关API，最后了解指令的解析运行原理">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/%E9%87%8D%E7%82%B9%E9%9A%BE%E7%82%B9%E8%BD%BB%E6%9D%BE%E4%BC%9A.png">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226162430.png">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226113801.png">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226161232.png">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226114146.png">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226120605.png">
<meta property="og:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226121342.png">
<meta property="article:published_time" content="2023-02-26T09:04:00.000Z">
<meta property="article:modified_time" content="2023-02-26T09:07:20.930Z">
<meta property="article:author" content="William Leung">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/%E9%87%8D%E7%82%B9%E9%9A%BE%E7%82%B9%E8%BD%BB%E6%9D%BE%E4%BC%9A.png">


<link rel="canonical" href="https://gitee.com/lianghuilin/murmur.git/crush_notes/%E6%8E%8C%E6%8F%A1%E4%B8%8E%E4%BD%BF%E7%94%A8Vue%E6%8C%87%E4%BB%A4/">


<script class="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>掌握与使用Vue指令 | 汇话板</title>
  


  <script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?a49081c570a782a242cdf6e19e1a584d";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




  <noscript>
  <style>
  body { margin-top: 2rem; }

  .use-motion .menu-item,
  .use-motion .sidebar,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header {
    visibility: visible;
  }

  .use-motion .header,
  .use-motion .site-brand-container .toggle,
  .use-motion .footer { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle,
  .use-motion .custom-logo-image {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line {
    transform: scaleX(1);
  }

  .search-pop-overlay, .sidebar-nav { display: none; }
  .sidebar-panel { display: block; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/murmur/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">汇话板</h1>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">设定目标，放慢步调，用温和的力量自我改革</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/murmur/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/murmur/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
  </ul>
</nav>




</div>
        
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <section class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B5%B7%E5%BF%83%E5%8A%A8%E5%BF%B5"><span class="nav-number">1.</span> <span class="nav-text">起心动念</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%9B%AE%E6%A0%87"><span class="nav-number">1.1.</span> <span class="nav-text">目标</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B0%81%E8%A3%85v-props-bind%E6%8C%87%E4%BB%A4"><span class="nav-number">2.</span> <span class="nav-text">封装v-props-bind指令</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#v-bind%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98%EF%BC%9F"><span class="nav-number">2.1.</span> <span class="nav-text">v-bind有什么问题？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%E4%B8%AD%EF%BC%8C%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%86%85%E7%BD%AE%E6%8C%87%E4%BB%A4%EF%BC%9F"><span class="nav-number">2.2.</span> <span class="nav-text">自定义指令中，如何使用内置指令？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AE%8C%E6%95%B4%E6%A1%88%E4%BE%8B%E4%BB%A3%E7%A0%81"><span class="nav-number">2.3.</span> <span class="nav-text">完整案例代码</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue%E6%8C%87%E4%BB%A4%E7%9A%84API%E8%B5%B0%E8%AF%BB"><span class="nav-number">3.</span> <span class="nav-text">Vue指令的API走读</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Vue%E4%B8%AD%E4%BB%A3%E7%A0%81%E7%9A%84%E5%B0%81%E8%A3%85%E6%96%B9%E5%BC%8F%E6%9C%89%E5%93%AA%E4%BA%9B%EF%BC%9F"><span class="nav-number">3.1.</span> <span class="nav-text">Vue中代码的封装方式有哪些？</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-%E6%8F%92%E4%BB%B6-Plugin"><span class="nav-number">3.1.1.</span> <span class="nav-text">1. 插件(Plugin)</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#1-%E6%89%A9%E5%B1%95%E8%83%BD%E5%8A%9B%E7%9A%84%E5%B7%A5%E5%85%B7%E5%BA%93"><span class="nav-number">3.1.1.1.</span> <span class="nav-text">(1) 扩展能力的工具库</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-%E5%BC%80%E7%AE%B1%E5%8D%B3%E7%94%A8%E7%9A%84UI%E7%BB%84%E4%BB%B6%E5%BA%93"><span class="nav-number">3.1.1.2.</span> <span class="nav-text">(2) 开箱即用的UI组件库</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-%E7%BB%84%E4%BB%B6-Component"><span class="nav-number">3.1.2.</span> <span class="nav-text">2. 组件(Component)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-%E6%B7%B7%E5%85%A5-Mixin"><span class="nav-number">3.1.3.</span> <span class="nav-text">3. 混入(Mixin)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-%E7%BB%84%E5%90%88%E5%BC%8F%E5%87%BD%E6%95%B0-Composable-Functions"><span class="nav-number">3.1.4.</span> <span class="nav-text">4. 组合式函数(Composable Functions)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-%E6%8C%87%E4%BB%A4-Directive"><span class="nav-number">3.1.5.</span> <span class="nav-text">5. 指令(Directive)</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Vue%E5%B8%B8%E8%A7%81%E7%9A%84%E6%8C%87%E4%BB%A4%E5%92%8C%E4%BF%AE%E9%A5%B0%E7%AC%A6%E6%9C%89%E5%93%AA%E4%BA%9B%EF%BC%9F"><span class="nav-number">3.2.</span> <span class="nav-text">Vue常见的指令和修饰符有哪些？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%90%8C%E6%97%B6%E7%94%A8v-for%E4%B8%8Ev-if%E4%BC%98%E5%85%88%E6%89%A7%E8%A1%8C%E5%93%AA%E4%B8%AA%EF%BC%9F%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E4%BC%98%E5%8C%96%EF%BC%9F"><span class="nav-number">3.3.</span> <span class="nav-text">同时用v-for与v-if优先执行哪个？如何进行优化？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#v-forkey%E7%9A%84%E4%BD%9C%E7%94%A8"><span class="nav-number">3.4.</span> <span class="nav-text">v-forkey的作用</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Vue2-3%E5%A6%82%E4%BD%95%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4%EF%BC%9F"><span class="nav-number">3.5.</span> <span class="nav-text">Vue2&#x2F;3如何自定义指令？</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%87%BD%E6%95%B0%E5%BC%8F%E4%B8%8E%E9%85%8D%E7%BD%AE%E7%9A%84%E5%A3%B0%E6%98%8E%E6%96%B9%E5%BC%8F"><span class="nav-number">3.5.1.</span> <span class="nav-text">函数式与配置的声明方式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Vue2%E4%B8%8E3%E6%8C%87%E4%BB%A4%E9%92%A9%E5%AD%90%E5%AF%B9%E6%AF%94"><span class="nav-number">3.5.2.</span> <span class="nav-text">Vue2与3指令钩子对比</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Vue3-withDirectives-resolveDirective-API"><span class="nav-number">3.6.</span> <span class="nav-text">Vue3 withDirectives()&#x2F;resolveDirective() API</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%B7%B1%E5%85%A5%E6%8C%87%E4%BB%A4%E5%8E%9F%E7%90%86"><span class="nav-number">4.</span> <span class="nav-text">深入指令原理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#v-if-v-show-v-html%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="nav-number">4.1.</span> <span class="nav-text">v-if&#x2F;v-show&#x2F;v-html的实现原理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#v-model%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="nav-number">4.2.</span> <span class="nav-text">v-model的实现原理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF%E8%A7%A3%E6%9E%90%E8%BF%90%E8%A1%8C%E7%9A%84%E5%8E%9F%E7%90%86"><span class="nav-number">4.3.</span> <span class="nav-text">模板解析运行的原理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B%E6%98%AF%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90%E6%8C%87%E4%BB%A4%E7%9A%84%EF%BC%9F"><span class="nav-number">4.3.1.</span> <span class="nav-text">模板编译过程是如何解析指令的？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%8C%87%E4%BB%A4%E7%9A%84%E9%92%A9%E5%AD%90%E5%A6%82%E4%BD%95%E7%94%9F%E6%95%88%E7%9A%84%EF%BC%9F"><span class="nav-number">4.3.2.</span> <span class="nav-text">指令的钩子如何生效的？</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#%E6%8C%87%E4%BB%A4%E5%8F%AA%E5%85%B3%E5%BF%83%E7%BB%84%E4%BB%B6%E7%9A%843%E4%B8%AA%E9%98%B6%E6%AE%B5"><span class="nav-number">4.3.2.1.</span> <span class="nav-text">指令只关心组件的3个阶段</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#%E9%80%9A%E8%BF%87%E6%8C%87%E4%BB%A4%E7%8A%B6%E6%80%81%E8%B0%83%E7%94%A8%E9%92%A9%E5%AD%90"><span class="nav-number">4.3.2.2.</span> <span class="nav-text">通过指令状态调用钩子</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%B8%A3%E8%B0%A2"><span class="nav-number">5.</span> <span class="nav-text">鸣谢</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%8B%B3%E8%84%9A%E6%A3%8D%E6%A3%92"><span class="nav-number">5.1.</span> <span class="nav-text">拳脚棍棒</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A6%82%E6%9D%A5%E7%A5%9E%E6%8E%8C"><span class="nav-number">5.2.</span> <span class="nav-text">如来神掌</span></a></li></ol></li></ol></div>
        </section>
        <!--/noindex-->

        <section class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">William Leung</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/murmur/archives">
          <span class="site-state-item-count">43</span>
          <span class="site-state-item-name">文章</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/murmur/categories/">
          
        <span class="site-state-item-count">9</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/murmur/tags/">
        <span class="site-state-item-count">1</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



        </section>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">
      

      

  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://gitee.com/lianghuilin/murmur.git/crush_notes/%E6%8E%8C%E6%8F%A1%E4%B8%8E%E4%BD%BF%E7%94%A8Vue%E6%8C%87%E4%BB%A4/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/murmur/images/avatar.gif">
      <meta itemprop="name" content="William Leung">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="汇话板">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          掌握与使用Vue指令
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2023-02-26 17:04:00 / 修改时间：17:07:20" itemprop="dateCreated datePublished" datetime="2023-02-26T17:04:00+08:00">2023-02-26</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/murmur/categories/%E9%97%AA%E5%BF%B5%E7%AC%94%E8%AE%B0/" itemprop="url" rel="index"><span itemprop="name">闪念笔记</span></a>
        </span>
    </span>

  
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>7.3k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>7 分钟</span>
    </span>
</div>

            <div class="post-description">演示自定义指令案例，通读了解指令相关API，最后了解指令的解析运行原理</div>
        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/%E9%87%8D%E7%82%B9%E9%9A%BE%E7%82%B9%E8%BD%BB%E6%9D%BE%E4%BC%9A.png"></p>
<p>[TOC]</p>
<h2 id="起心动念"><a href="#起心动念" class="headerlink" title="起心动念"></a>起心动念</h2><p>早年，去“招商城科”面试，当时面试官为了考察我对Vue框架的熟悉程度，就问了一系列Vue指令的问题，当时自己是个铁憨憨，没回答好。本以为会换来一句，“那你回去等通知吧”，可面试官没有赶我走，反而很和善跟我分享，他说除了组件之外，指令也是Vue框架极具魅力的特点之一，修饰符是典型的装饰器模式等等，让我感念至今。</p>
<p>前不久，项目中刚好遇到封装一个<code>v-props-bind</code>指令的需求，索性趁着这个机会，系统整理一下关于Vue指令的知识点与所思所想。</p>
<h3 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h3><p>我们通过以下3个目标，完成对Vue指令的整理与掌握：</p>
<ol>
<li>自定义指令的创建与使用</li>
<li>走读Vue指令相关的API</li>
<li>了解指令解析到运行的原理</li>
</ol>
<h2 id="封装v-props-bind指令"><a href="#封装v-props-bind指令" class="headerlink" title="封装v-props-bind指令"></a>封装<code>v-props-bind</code>指令</h2><h3 id="v-bind有什么问题？"><a href="#v-bind有什么问题？" class="headerlink" title="v-bind有什么问题？"></a><code>v-bind</code>有什么问题？</h3><p>我们都知道，内置指令<code>v-bind</code>是对组件进行attribute/props属性绑定，如下面动态渲染<code>Input</code>组件的例子，已定义的<code>options</code>和<code>position</code>属性会进行Props传递赋值，未定义的<code>id</code>、<code>datasetId</code>、<code>component</code>属性会转成DOM对象的attribute属性暴露到页面上。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// config.js</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> [</span><br><span class="line">  &#123;</span><br><span class="line">    id: <span class="string">&quot;1471EB96-BBCF-303F-DB22-4EEEB0032D5C&quot;</span>,</span><br><span class="line">    component: <span class="string">&quot;Input&quot;</span>,</span><br><span class="line">    datasetId: <span class="string">&quot;D19867BE-3750-E7E8-1ED2-4457AF95D9EC&quot;</span>,</span><br><span class="line">    options: &#123;</span><br><span class="line">      placehold: <span class="string">&quot;请输入昵称&quot;</span>,</span><br><span class="line">      disabled: <span class="literal">false</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">    position: &#123;</span><br><span class="line">      width: <span class="string">&quot;200px&quot;</span>,</span><br><span class="line">      height: <span class="string">&quot;20px&quot;</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment">// Input.vue 的props定义</span></span><br><span class="line">defineProps(&#123;</span><br><span class="line">  options: &#123;</span><br><span class="line">    required: <span class="literal">false</span>,</span><br><span class="line">    <span class="keyword">default</span>: &#123;</span><br><span class="line">      placehold: <span class="string">&quot;请输入&quot;</span>,</span><br><span class="line">      disabled: <span class="literal">true</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  position: &#123;</span><br><span class="line">    required: <span class="literal">false</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span> <span class="attr">v-for</span>=<span class="string">&quot;config in kanbanComponentList&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;config.id&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- v-bind会对整个config对象进行绑定 --&gt;</span></span><br><span class="line">        &lt;component</span><br><span class="line">          :is=&quot;componentMap[config.component]&quot;</span><br><span class="line">          v-bind=&quot;config&quot;</span><br><span class="line">        &gt;<span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">&lt;!-- 渲染出来的DOM是这样婶的 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">data-v-469af010</span>=<span class="string">&quot;&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;请输入昵称&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">component</span>=<span class="string">&quot;Input&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">id</span>=<span class="string">&quot;1471EB96-BBCF-303F-DB22-4EEEB0032D5C&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">datasetId</span>=<span class="string">&quot;D19867BE-3750-E7E8-1ED2-4457AF95D9EC&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">style</span>=<span class="string">&quot;width: 500px; height: 20px;&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">         <span class="comment">&lt;!-- 但我们期望渲染成这样 --&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="name">input</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">data-v-469af010</span>=<span class="string">&quot;&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;请输入昵称&quot;</span> </span></span><br><span class="line"><span class="tag">            <span class="attr">style</span>=<span class="string">&quot;width: 500px; height: 20px;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>虽然把额外的配置属性转成HTML attribute属性，给暴露到页面上也没有报错，但这显然是不合适的。</p>
<p>所以，我们能不能封装一个<code>v-props-bind</code>指令，当配置对象进行绑定时，能根据当前组件定义的<code>props key</code>过滤绑定的数据。</p>
<h3 id="自定义指令中，如何使用内置指令？"><a href="#自定义指令中，如何使用内置指令？" class="headerlink" title="自定义指令中，如何使用内置指令？"></a>自定义指令中，如何使用内置指令？</h3><p>一开始，想着在自定义指令的生命周期钩子里面，筛选数据后，直接调用<code>v-bind</code>进行数据绑定的。然而找了一圈资料，四处问人，也没有找到在JS代码中应用内置指令的办法。于是转换思路，将要绑定的数据赋值到<code>vnode</code>对象中。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// setup中创建指令</span></span><br><span class="line"><span class="keyword">const</span> vPropsBind = &#123;</span><br><span class="line">  beforeMount (el, binding, vnode) &#123;</span><br><span class="line">      <span class="keyword">const</span> &#123; value &#125; = binding;</span><br><span class="line">      <span class="keyword">const</span> &#123;</span><br><span class="line">          ctx: &#123; props &#125;,</span><br><span class="line">      &#125; = vnode;</span><br><span class="line">      <span class="comment">// 根据组件propKeys进行数据绑定</span></span><br><span class="line">      <span class="keyword">const</span> propKeys = <span class="built_in">Object</span>.keys(props);</span><br><span class="line">      propKeys.forEach(<span class="function">(<span class="params">propKey</span>) =&gt;</span> &#123;</span><br><span class="line">          props[propKey] = value[propKey];</span><br><span class="line">      &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 视图中运用指令 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">component</span> <span class="attr">:is</span>=<span class="string">&quot;config.component&quot;</span> <span class="attr">v-props-bind</span>=<span class="string">&quot;config&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h3 id="完整案例代码"><a href="#完整案例代码" class="headerlink" title="完整案例代码"></a>完整案例代码</h3><p><a href="https://gitee.com/lianghuilin/demo-custom-directive-bind-props">https://gitee.com/lianghuilin/demo-custom-directive-bind-props</a></p>
<h2 id="Vue指令的API走读"><a href="#Vue指令的API走读" class="headerlink" title="Vue指令的API走读"></a>Vue指令的API走读</h2><h3 id="Vue中代码的封装方式有哪些？"><a href="#Vue中代码的封装方式有哪些？" class="headerlink" title="Vue中代码的封装方式有哪些？"></a>Vue中代码的封装方式有哪些？</h3><h4 id="1-插件-Plugin"><a href="#1-插件-Plugin" class="headerlink" title="1. 插件(Plugin)"></a>1. 插件(Plugin)</h4><p>通过<code>Vue.use()</code>注册使用的全局的类库，通常是单例的。大致有两大类：</p>
<h5 id="1-扩展能力的工具库"><a href="#1-扩展能力的工具库" class="headerlink" title="(1) 扩展能力的工具库"></a>(1) 扩展能力的工具库</h5><p>比如官方提供的 <code>vue-router</code>路由管理库，<code>Vuex</code>状态管理库</p>
<h5 id="2-开箱即用的UI组件库"><a href="#2-开箱即用的UI组件库" class="headerlink" title="(2) 开箱即用的UI组件库"></a>(2) 开箱即用的UI组件库</h5><p>比如(<code>element-ui</code>/<code>iview</code>/<code>Vuetify</code>)，各类移动端/PC端的UI库，提供</p>
<h4 id="2-组件-Component"><a href="#2-组件-Component" class="headerlink" title="2. 组件(Component)"></a>2. 组件(Component)</h4><p>日常最熟悉的代码封装方式，通常将可复用的视图和交互逻辑封装到一个以<code>.vue</code>后缀的文件组织的SFC(single file component)中。组件可以相互嵌套，具有相似的生命周期钩子。最终可以注册成为全局组件，也可以注册成局部组件。</p>
<h4 id="3-混入-Mixin"><a href="#3-混入-Mixin" class="headerlink" title="3. 混入(Mixin)"></a>3. 混入(Mixin)</h4><p>Vue2的代码封装方式，所谓Mixin对象实际上就是组件的可复用选项(option)，比如data/methods/computed等。目标组件的<code>mixins</code>配置项可以“混入合并”多个mixin对象。</p>
<h4 id="4-组合式函数-Composable-Functions"><a href="#4-组合式函数-Composable-Functions" class="headerlink" title="4. 组合式函数(Composable Functions)"></a>4. 组合式函数(Composable Functions)</h4><p>Vue3的代码封装方式，和React Hooks一样，本质就是闭包函数，封装复用那些有状态的业务逻辑，用以替代Vue2 <code>Mixin</code>。</p>
<h4 id="5-指令-Directive"><a href="#5-指令-Directive" class="headerlink" title="5. 指令(Directive)"></a>5. 指令(Directive)</h4><p>Vue提供一系列的内置指令并允许自定义指令，进行视图层的逻辑控制，比如<code>v-if</code>/<code>v-show</code>/<code>v-for</code>。<br>其实指令能控制从<code>template</code>到<code>vnode</code>再到挂载后的<code>DOM</code>，的每一层对象。<br>这也是为什么Vue不属于纯粹的MVVM框架的地方，它不但能操作<code>Virtual DOM</code>，还直接操作真实DOM，相当于补上了配送的最后一里路。</p>
<h3 id="Vue常见的指令和修饰符有哪些？"><a href="#Vue常见的指令和修饰符有哪些？" class="headerlink" title="Vue常见的指令和修饰符有哪些？"></a>Vue常见的指令和修饰符有哪些？</h3><p>简单罗列一下Vue的指令，详情参考Vue官网</p>
<table>
<thead>
<tr>
<th>指令</th>
<th>一句话解释</th>
</tr>
</thead>
<tbody><tr>
<td>v-if</td>
<td>根据表达式，判断视图渲染</td>
</tr>
<tr>
<td>v-show</td>
<td>根据表达式，判断DOM元素的display属性是否显示</td>
</tr>
<tr>
<td>v-show</td>
<td>进行视图的循环渲染</td>
</tr>
<tr>
<td>v-bind</td>
<td>进行组件的属性绑定（attribute或者props）</td>
</tr>
<tr>
<td>v-on</td>
<td>进行组件的事件绑定，并可通过一系列修饰符如<code>.stop</code>/<code>.prevent</code>/<code>.once</code>等改变事件的行为</td>
</tr>
<tr>
<td>v-pre</td>
<td>跳过编译，直接显示template中的Mustache标签</td>
</tr>
<tr>
<td>v-once</td>
<td>组件只渲染一次，此后都视为静态内容，跳过diff检查</td>
</tr>
<tr>
<td>v-model</td>
<td>对输入场组件，如input/select等，进行双向数据绑定</td>
</tr>
<tr>
<td>v-memo</td>
<td>Vue3.2新增，指定组件缓存。当v-memo=”[]”时，与v-once效果相同</td>
</tr>
<tr>
<td>v-clock</td>
<td>当DOM未完成编译前隐藏该元素，避免白屏的闪烁效果</td>
</tr>
</tbody></table>
<h3 id="同时用v-for与v-if优先执行哪个？如何进行优化？"><a href="#同时用v-for与v-if优先执行哪个？如何进行优化？" class="headerlink" title="同时用v-for与v-if优先执行哪个？如何进行优化？"></a>同时用<code>v-for</code>与<code>v-if</code>优先执行哪个？如何进行优化？</h3><p><strong>Vue2中<code>v-for</code>优先级更高，而Vue3中<code>v-if</code>优先级更高。</strong></p>
<p>优先级文档：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://v2.cn.vuejs.org/v2/guide/list.html#v-for-object">https://v2.cn.vuejs.org/v2/guide/list.html#v-for-object</a></li>
<li><a target="_blank" rel="noopener" href="https://cn.vuejs.org/api/built-in-directives.html#v-if">https://cn.vuejs.org/api/built-in-directives.html#v-if</a></li>
</ul>
<p>优化分两种情况：</p>
<ul>
<li>如果是想先进行判断，再进行循环。可以在<code>v-for</code>代码再套一层父节点<code>&lt;template v-if&gt;</code>进行判断，使得代码层次看起来更清晰。</li>
<li>如果是想先循环后判断，对则可以提前通过<code>computed</code>进行处理，视图<code>template</code>仅负责循环渲染。</li>
</ul>
<p>优化文档：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://cn.vuejs.org/guide/essentials/list.html#v-for-with-v-if">https://cn.vuejs.org/guide/essentials/list.html#v-for-with-v-if</a></li>
<li><a target="_blank" rel="noopener" href="https://v2.cn.vuejs.org/v2/guide/conditional.html#v-if-%E4%B8%8E-v-for-%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8">https://v2.cn.vuejs.org/v2/guide/conditional.html#v-if-%E4%B8%8E-v-for-%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8</a></li>
</ul>
<h3 id="v-forkey的作用"><a href="#v-forkey的作用" class="headerlink" title="v-forkey的作用"></a><code>v-for</code>key的作用</h3><p>循环渲染视图时，通过key对<code>vnode</code>对象进行唯一标识，从而计算机因为下标进行数组对比带来的更新问题</p>
<h3 id="Vue2-3如何自定义指令？"><a href="#Vue2-3如何自定义指令？" class="headerlink" title="Vue2/3如何自定义指令？"></a>Vue2/3如何自定义指令？</h3><h4 id="函数式与配置的声明方式"><a href="#函数式与配置的声明方式" class="headerlink" title="函数式与配置的声明方式"></a>函数式与配置的声明方式</h4><p>Vue2可以通过<code>directives</code>配置项的方式创建指令，Vue3 setup中则更简介，只要声明以小写<code>v</code>开头驼峰命名的对象变量即可。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 配置项的声明方式</span></span><br><span class="line"><span class="keyword">const</span> focust = &#123;</span><br><span class="line">    mounted: <span class="function">(<span class="params">el</span>) =&gt;</span> el.focus()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    directives: &#123;</span><br><span class="line">        focus</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// setup下的声明方式</span></span><br><span class="line"><span class="keyword">const</span> vFocus = &#123;</span><br><span class="line">    mounted: <span class="function">(<span class="params">el</span>) =&gt;</span> el.focus()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="Vue2与3指令钩子对比"><a href="#Vue2与3指令钩子对比" class="headerlink" title="Vue2与3指令钩子对比"></a>Vue2与3指令钩子对比</h4><table>
<thead>
<tr>
<th>Vue2指令</th>
<th>Vue3指令</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td><strong>bind</strong></td>
<td></td>
<td>指令第一次绑定到元素时调用，可进行初始化操作</td>
</tr>
<tr>
<td></td>
<td><strong>created</strong></td>
<td>在元素attribute和事件绑定前调用</td>
</tr>
<tr>
<td></td>
<td><strong>beforeMount</strong></td>
<td>在元素被插入DOM前调用</td>
</tr>
<tr>
<td><strong>inserted</strong></td>
<td><strong>mounted</strong></td>
<td>在绑定元素的父组件+元素自己+所有子节点都挂载完成后调用</td>
</tr>
<tr>
<td><strong>update</strong></td>
<td><strong>beforeUpdate</strong></td>
<td>绑定元素的父组件更新前调用</td>
</tr>
<tr>
<td><strong>componentUpdated</strong></td>
<td><strong>updated</strong></td>
<td>绑定元素的父组件+元素自己+所有子节点都更新后调用</td>
</tr>
<tr>
<td><strong>unbind</strong></td>
<td><strong>beforeUnmount</strong></td>
<td>绑定元素的父组件卸载之前调用</td>
</tr>
<tr>
<td></td>
<td><strong>unmounted</strong></td>
<td>绑定元素的父组件卸载后调用</td>
</tr>
</tbody></table>
<p>文档参考：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://v2.cn.vuejs.org/v2/guide/custom-directive.html">https://v2.cn.vuejs.org/v2/guide/custom-directive.html</a></li>
<li><a target="_blank" rel="noopener" href="https://cn.vuejs.org/guide/reusability/custom-directives.html">https://cn.vuejs.org/guide/reusability/custom-directives.html</a></li>
</ul>
<h3 id="Vue3-withDirectives-resolveDirective-API"><a href="#Vue3-withDirectives-resolveDirective-API" class="headerlink" title="Vue3 withDirectives()/resolveDirective() API"></a>Vue3 <code>withDirectives()</code>/<code>resolveDirective()</code> API</h3><ul>
<li><code>withDirectives</code>给vnode对象添加自定义指令，并返回这个vnode对象</li>
<li><code>resolveDirective()</code>按名称解析已注册的指令</li>
</ul>
<p>文档参考：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://cn.vuejs.org/api/render-function.html#resolvedirective">https://cn.vuejs.org/api/render-function.html#resolvedirective</a></li>
<li><a target="_blank" rel="noopener" href="https://cn.vuejs.org/api/render-function.html#withdirectives">https://cn.vuejs.org/api/render-function.html#withdirectives</a></li>
</ul>
<h2 id="深入指令原理"><a href="#深入指令原理" class="headerlink" title="深入指令原理"></a>深入指令原理</h2><h3 id="v-if-v-show-v-html的实现原理"><a href="#v-if-v-show-v-html的实现原理" class="headerlink" title="v-if/v-show/v-html的实现原理"></a><code>v-if</code>/<code>v-show</code>/<code>v-html</code>的实现原理</h3><p>如上面提到的，<code>v-if</code>在template解析的时候，会根据表达式结果跳过vnode的生成，而<code>v-show</code>会生成vnode对象，render也会生成对应的DOM节点，只是表达式结果，修改display属性进行隐藏或显示<br>而<code>v-html</code>渲染流程是先移除当前元素下的所有子节点，然后设置innerHTML的值为<code>v-html</code>的值。</p>
<h3 id="v-model的实现原理"><a href="#v-model的实现原理" class="headerlink" title="v-model的实现原理"></a><code>v-model</code>的实现原理</h3><ul>
<li>“响应式数据”和“双向数据绑定”是两个概念，“响应式数据”是指数据驱动VDOM，无需操作DOM就能实现视图的刷新，是单向的；而“双向数据绑定”是双向的，不但JS数据能刷新视图，视图的输入也能改变JS数据</li>
<li><code>v-model</code>就是双向数据绑定的应用，以<code>&lt;input v-model=&quot;firstName&quot;&gt;</code>为例，它是<code>&lt;input v-bind:value=&quot;firstName&quot; v-on:change=&quot;(val) =&gt; firstName = value&quot;&gt;</code>的语法糖</li>
<li><code>v-model</code>不但可以在<code>input</code>/<code>select</code>/<code>raio</code>等表单组件使用，也可以在自定义组件中使用；Vue3还可以在同一个组件中，多个绑定<code>v-model</code>的双向数据</li>
</ul>
<h3 id="模板解析运行的原理"><a href="#模板解析运行的原理" class="headerlink" title="模板解析运行的原理"></a>模板解析运行的原理</h3><p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226162430.png"></p>
<h4 id="模板编译过程是如何解析指令的？"><a href="#模板编译过程是如何解析指令的？" class="headerlink" title="模板编译过程是如何解析指令的？"></a>模板编译过程是如何解析指令的？</h4><ol>
<li><strong>baseParse阶段</strong> ：<code>&lt;template&gt;</code>进行词法分析，生成AST；</li>
<li><strong>transform阶段</strong> ：将AST Element进行转换，其中就包含指令的转换；</li>
<li><strong>generator阶段</strong> ：将AST Element生成可执行的<code>render</code>函数，执行<code>render</code>函数可得到<code>vnode</code>对象；</li>
<li><strong>patch阶段</strong> ：得到vnode对象后，指令挂载在<code>vNode.data.directives</code>属性上；</li>
<li><strong>mounted阶段</strong> ：通过vnode对象生成真实的DOM；</li>
</ol>
<h4 id="指令的钩子如何生效的？"><a href="#指令的钩子如何生效的？" class="headerlink" title="指令的钩子如何生效的？"></a>指令的钩子如何生效的？</h4><h5 id="指令只关心组件的3个阶段"><a href="#指令只关心组件的3个阶段" class="headerlink" title="指令只关心组件的3个阶段"></a>指令只关心组件的3个阶段</h5><p>虽然组件的生命周期钩子很多，但对于指令来说，只关心vnode渲染的<code>create</code>，<code>update</code>，<code>destroy</code>三个阶段。<br>所以只需要监听这三个阶段，执行<code>updateDirectives</code>函数来处理指令的相关逻辑：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  create: updateDirectives,</span><br><span class="line">  update: updateDirectives,</span><br><span class="line">  destroy: <span class="function"><span class="keyword">function</span> <span class="title">unbindDirectives</span> (<span class="params">vnode: VNodeWithData</span>) </span>&#123;</span><br><span class="line">    updateDirectives(vnode, emptyNode)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="通过指令状态调用钩子"><a href="#通过指令状态调用钩子" class="headerlink" title="通过指令状态调用钩子"></a>通过指令状态调用钩子</h5><p>创建指令时，配置对象定义了几个钩子函数，这些钩子分别对应着指令的几种状态。<code>updateDirectives</code>函数就是对比新旧vnode对象的指令列表，然后执行不同的钩子函数，让指令生效。</p>
<p>文档参考：<a target="_blank" rel="noopener" href="https://vue-js.com/learn-vue/directives/customDirectives.html">https://vue-js.com/learn-vue/directives/customDirectives.html</a></p>
<h2 id="鸣谢"><a href="#鸣谢" class="headerlink" title="鸣谢"></a>鸣谢</h2><p>最后，我想说说周星驰的电影《功夫》的开头和结尾两场戏。</p>
<h3 id="拳脚棍棒"><a href="#拳脚棍棒" class="headerlink" title="拳脚棍棒"></a>拳脚棍棒</h3><p>《功夫》除了是一部老少咸宜的喜剧片之外，更难得的是它包含了周星驰对于中华武学的深层理解。</p>
<p>电影的第一场高潮戏就是因为周星驰假扮斧头帮收保护费，结果惹来了真的斧头帮。</p>
<p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226113801.png"></p>
<p>危难之际，猪笼城寨里擀面的阿鬼( <em>五郎八卦棍</em> )，裁缝店的娘娘腔( <em>洪家铁线拳</em> )，还有沉默的苦力强( <em>少林十二路谭腿</em> )挺身而出，打跑了斧头帮。</p>
<p>这三人刻意的出场顺序，实际就对应了他们的武力值排行： <strong>先腿，后拳，再兵器</strong> 。</p>
<p>而在周星驰看来， <strong><em>习武之人，基本功就是扎马步。等腿有力，下盘结实了，才可以学拳。拳脚功夫可以了，才能碰兵器。</em></strong>  这是学功夫的过程，顺序不能乱。</p>
<p>而我们学技术也是要循序渐进，要有足够的耐心。从打基础开始，然后慢慢到接触不同的框架/工具。当然，过程中总会有人会抨击你：</p>
<ul>
<li>“Vue这么简单，还要学吗？”</li>
<li>“React还要学吗？不就跟Vue一样吗？”</li>
<li>“居然还在看CSS，这有什么难的？”</li>
</ul>
<p>别人眼高手低，但自己不要被CPU就好。学基础不丢人，工作经验好几年了，如果基础还这么差劲才丢人呢！</p>
<h3 id="如来神掌"><a href="#如来神掌" class="headerlink" title="如来神掌"></a>如来神掌</h3><p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226161232.png"></p>
<p>电影《功夫》的最后一幕，周星驰最终破茧成蝶，用如来神掌打败了火云邪神。而面对偷袭，周星驰一掌击垮了一幢楼，故意打偏的。</p>
<p>意思很明确，我有能力，也有理由干掉你，但我没有这么做。火云邪神，呆住了。</p>
<p>火云邪神是武痴，他的世界里，赢就是唯一准则，即便是偷袭，即便是杀人。他不理解周星驰的如来神掌为什么这么厉害，更不理解如何能做到“止杀”。怔怔问道“这是什么武功？”</p>
<p>周星驰只是把他偷袭的武器，化作竹蜻蜓飞走了，笑着问他“想学吗，我教你啊”</p>
<p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226114146.png"></p>
<p>当然，在“耗子尾汁”，“年轻人不讲武德”等表情包横行的当下，<strong>“以德服人”</strong> 这四个字，看起来就TM是搞笑的。</p>
<p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226120605.png"></p>
<p>但电影中，周星驰的确通过化干戈为玉帛，做到了老乞丐说的“维护世界和平的重任”。而不是以暴制暴，更不是以杀止杀。</p>
<hr>
<p>OK，电影说完了，回到做技术这件事。不可否认，技术圈也是有鄙视链的。</p>
<p>在职场上，要是你基础不扎实，学习态度还不端正，就难免会被人鄙视。又菜又哇哇叫的，当然是不讨人喜欢的。</p>
<p>而面试的场合就更不必说了，本就是在有限的时间内，一个人要对另一个人进行审视和考验，对话双方的地位天然就是不对等的，会放大这种鄙视的感觉。</p>
<p>所以，最后我还想再次感谢“招商城科”面试我的大佬。能够跳脱出当下，用平等/尊重/和善的态度沟通对话。跟我想朋友一样，聊Vue的指令，也给了我学习的动力，让我想成为跟你一样的大佬！</p>
<p><img src="https://gitee.com/lianghuilin/blog-image-warehouse/raw/master/20230226121342.png"></p>

    </div>

    
    
    

    <footer class="post-footer">
          

<div class="post-copyright">
<ul>
  <li class="post-copyright-author">
      <strong>本文作者： </strong>William Leung
  </li>
  <li class="post-copyright-link">
      <strong>本文链接：</strong>
      <a href="https://gitee.com/lianghuilin/murmur.git/crush_notes/%E6%8E%8C%E6%8F%A1%E4%B8%8E%E4%BD%BF%E7%94%A8Vue%E6%8C%87%E4%BB%A4/" title="掌握与使用Vue指令">https://gitee.com/lianghuilin/murmur.git/crush_notes/掌握与使用Vue指令/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/murmur/vue3_practice/TS%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6Props%E7%9A%84default%E5%92%8Crequired/" rel="prev" title="TS定义组件Props的default和required">
                  <i class="fa fa-chevron-left"></i> TS定义组件Props的default和required
                </a>
            </div>
            <div class="post-nav-item">
            </div>
          </div>
    </footer>
  </article>
</div>






      

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      const activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      const commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

    </div>
  </main>

  <footer class="footer">
    <div class="footer-inner">
      

      

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">William Leung</span>
</div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
    <span title="站点总字数">142k</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">2:09</span>
  </span>
</div>
<div class="busuanzi-count">
    <span id="busuanzi_container_site_uv">
      本站访客数<span id="busuanzi_value_site_uv"></span>人次
    </span>
    <span id="busuanzi_container_site_pv">
        本站总访问量<span id="busuanzi_value_site_pv"></span>次
    </span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <script src="//cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>
<script src="/murmur/js/utils.js"></script><script src="/murmur/js/motion.js"></script><script src="/murmur/js/next-boot.js"></script>

  
















  <script>
    NProgress.configure({
      showSpinner: true
    });
    NProgress.start();
    document.addEventListener('readystatechange', () => {
      if (document.readyState === 'interactive') {
        NProgress.inc(0.8);
      }
      if (document.readyState === 'complete') {
        NProgress.done();
      }
    });
    document.addEventListener('pjax:send', () => {
      NProgress.start();
    });
    document.addEventListener('pjax:success', () => {
      NProgress.done();
    });
  </script>


  
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>








  

  

</body>
</html>
